package com.haiheng.library_base.http

import android.text.TextUtils
import com.haiheng.library.log.LogUtils
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.MultipartBody
import okhttp3.RequestBody.Companion.asRequestBody
import java.io.File
import java.io.UnsupportedEncodingException
import java.net.URLConnection
import java.net.URLEncoder
import java.util.LinkedHashSet
import java.util.regex.Pattern

/**
 *
 * @Des: http请求体
 * @Author: hwz
 * @Date:2022/4/15 0015
 * @Version: 1.0
 */
open class HttpRequest @JvmOverloads constructor(
    private var url: String = "",
    private var path: MutableMap<String, String> = HashMap(),
    private var query: MutableMap<String, String> = HashMap(),
    private var header: MutableMap<String, String> = HashMap(),
    private var params: MutableMap<String, String> = HashMap(),

    private var files: MutableMap<String, File> = HashMap(),
    private var jsonObje :Any = Any(),
    private val queryParams: MutableMap<String, List<String>> = mutableMapOf<String, List<String>>()
) {

    fun setJsonObjec(objec: Any):HttpRequest{
        this.jsonObje =  objec
        return this
    }

    fun getParamsObjec():Any{
        return jsonObje
    }

    fun setUrl(url: String): HttpRequest {
        this.url = url
        return this
    }

    fun getUrl(
        baseUrl: String? = null,
//        templateUrl: String,
//        pathVariables: Map<String, String> = emptyMap(),
//        query: Map<String, String> = emptyMap(),
//        queryParams: Map<String, List<String>> = emptyMap()
    ): String {
        val matcher = Pattern.compile("\\{([a-zA-Z][a-zA-Z0-9_-]*)\\}").matcher(url)
        val patterns: MutableSet<String> = LinkedHashSet()
        while (matcher.find()) {
            matcher.group(1)?.let {
                patterns.add(it)
            }
        }
        patterns.forEach {
            if (path.contains(it)) {
                url = url.replace("{$it}", path[it].toString())
            }
        }
        LogUtils.d("getUrl:${url}")

        // 构建查询字符串
        val queryBuilder = StringBuilder()
        if (query.isNotEmpty()) {
            query.forEach { (key, value) ->
                if (queryBuilder.isNotEmpty()) {
                    queryBuilder.append("&")
                }
                queryBuilder.append(key).append("=").append(value)
            }
        }
        LogUtils.d("getUrl queryBuilder :${queryBuilder}")
        if (queryParams.isNotEmpty()) {
            queryParams.forEach { (key, values) ->
                values.forEachIndexed { index, value ->
                    if (queryBuilder.isNotEmpty() || index > 0) {
                        queryBuilder.append("&")
                    }
                    queryBuilder.append(key).append("=").append(value)
                }
            }
        }
//        LogUtils.d("getUrl queryBuilder :${queryBuilder}")

        // 合并基础 URL 和查询字符串
        val fullUrlBuilder = StringBuilder(url)
        if (queryBuilder.isNotEmpty()) {
            if (!url.contains("?")) {
                fullUrlBuilder.append("?")
            }
            fullUrlBuilder.append(queryBuilder)
        }
        LogUtils.d("getUrl fullUrlBuilder :${fullUrlBuilder}")
        // 如果提供了基础 URL，则添加它
        if (baseUrl != null) {
            val absoluteUrlBuilder = StringBuilder(baseUrl)
            if (!baseUrl.endsWith("/") && !url.startsWith("/")) {
                absoluteUrlBuilder.append("/")
            }
            absoluteUrlBuilder.append(fullUrlBuilder)
//            LogUtils.d("getUrl 提供了基础 URL absoluteUrlBuilder :${absoluteUrlBuilder}")
            return absoluteUrlBuilder.toString()
        }

        return fullUrlBuilder.toString()
    }

    fun getUrl1(baseUrl: String? = null): String {
        val matcher = Pattern.compile("\\{([a-zA-Z][a-zA-Z0-9_-]*)\\}").matcher(url)
        val patterns: MutableSet<String> = LinkedHashSet()
        while (matcher.find()) {
            matcher.group(1)?.let {
                patterns.add(it)
            }
        }
        patterns.forEach {
            if (path.contains(it)) {
                url = url.replace("{$it}", path[it].toString())
            }
        }
        val relativeUrl = StringBuilder(url)
        if (query.isNotEmpty()) {
            val absoluteUrl = StringBuilder()
            baseUrl?.apply { absoluteUrl.append(this) }
            absoluteUrl.append(url)
            if (!absoluteUrl.contains("?")) {
                relativeUrl.append("?")
            }
            if (!relativeUrl.endsWith("?")) {
                relativeUrl.append("&")
            }
            query.forEach { (key, value) ->
                relativeUrl.append(key).append("=").append(value).append("&")
            }

            relativeUrl.setLength(relativeUrl.length - 1)
        }

        val queryStringBuilder = StringBuilder(url)
        if (queryParams.isNotEmpty()) {
            val neaabsoluteUrl = StringBuilder()
            baseUrl?.apply { neaabsoluteUrl.append(this) }
            neaabsoluteUrl.append(url)
            if (!neaabsoluteUrl.contains("?")) {
                queryStringBuilder.append("?")
            }
            if (!queryStringBuilder.endsWith("?")) {
                queryStringBuilder.append("&")
            }


            LogUtils.d("queryStringBuilder1:${queryStringBuilder}")
            queryParams.forEach { (key, values) ->
                LogUtils.d("queryStringBuilder2:${key} ${values.size}")

                values.forEachIndexed { index, value ->
                    LogUtils.d("queryStringBuilder2:${index} ${value}")
                    if (index > 0) {
                        queryStringBuilder.append("&")
                    }
                    queryStringBuilder.append("$key=$value")
                    LogUtils.d("queryStringBuilder3:${queryStringBuilder}")

                }
            }
//            queryStringBuilder.setLength(queryStringBuilder.length - 1)
            LogUtils.d("queryStringBuilder4:${queryStringBuilder}")
        }
        if (queryParams.isNotEmpty()){
            LogUtils.d("${queryParams.size}连接：${queryStringBuilder.toString()}")
            return queryStringBuilder.toString()
        }else{
            return relativeUrl.toString()
        }

    }

    fun putPath(key: String, value: String): HttpRequest {
        if (!TextUtils.isEmpty(value)) {
            this.path[key] = value
        }
        return this
    }
//
//    // 添加单个查询参数（如果参数已存在，则替换其值）
//    fun addQueryParam(key: String, value: String) {
//        queryParams[key] = listOf(value)
//    }

    // 添加多个查询参数（对于同一键）
    fun putQueryParams(key: String, values: List<String>): HttpRequest {
        queryParams[key] = values
        return this
    }
    fun putQuery(key: String, value: String): HttpRequest {
        if (!TextUtils.isEmpty(value)) {
            this.query[key] = value
        }
        return this
    }

    fun putHeader(key: String, value: String): HttpRequest {
        this.header[key] = value
        return this
    }

    fun getHeader(): MutableMap<String, String> {
        return header
    }

    fun putParam(key: String, value: String): HttpRequest {
        this.params[key] = value
        return this
    }

    fun setParam(map:HashMap<String,String>):HttpRequest{
        this.params  = map;
        return this
    }

    fun getParam(): MutableMap<String, String> {
        return params
    }

    fun putFile(key: String, file: File): HttpRequest {
        this.files[key] = file
        return this
    }

    fun getFile(): MutableMap<String, File> {
        return files
    }

    fun getMultipartBody(): MultipartBody {
        val body = MultipartBody.Builder().setType(MultipartBody.FORM)
        getParam().forEach {
            body.addFormDataPart(it.key, it.value)
        }
        getFile().forEach {
            it.value.apply {
                val lastIndex = absolutePath.lastIndexOf("/")
                val fileName = absolutePath.substring(lastIndex)
                if (fileName.isNotEmpty()) {
                    val requestBody = asRequestBody(guessMimeType(fileName))
                    body.addFormDataPart(it.key, fileName, requestBody)
                }
            }
        }
        return body.build()
    }

    private fun guessMimeType(path: String): MediaType {
        val fileNameMap = URLConnection.getFileNameMap()
        var contentTypeFor = "application/octet-stream"
        try {
            fileNameMap.getContentTypeFor(URLEncoder.encode(path, "UTF-8")).also {
                if (it.isBlank()) {
                    contentTypeFor = it
                }
            }
        } catch (e: UnsupportedEncodingException) {
            e.printStackTrace()
        }
        return contentTypeFor.toMediaType()
    }

}